第二章 CSS 工作原理

发表于 2017-12-26 11:21:37 | 分类于 CSS |

剖析 CSS 规则

规则是一条完整的CSS 指令。规则声明了要修改的元素和要应用给该元素 的样式。

p {color:red;}

为文档添加样式的三种方法

  • 行内样式:写在元素标签里
  • 嵌入样式:写在 <style> 标签里
  • 链接样式:写在单独的CSS 样式表中

行内样式

行内样式的作用范围非常有限。行内样式只能影响它所在的标签,而且总会覆盖嵌入样式和链接样式。

嵌入样式

嵌入的CSS 样式放在HTML 文档的 <head> 元素。嵌入样式的应用范围仅限于当前页面。页面样式会覆盖外部样式表中的样式,但会被行内样式覆盖。

链接样式

在创建包含多个页面的网站时,需要把样式集中在一个单独的文件里,这个文件就叫样式表。

样式表是一个扩展名为.css 的文本文件。可以在任意多个HTML 页面中链接同一个样式表文件。

每个页面中只需加入类似下面的这一行代码即可: <link href="styles.css" rel="stylesheet" type="text/css" />

链接样式的作用范围可以是整个网站。

只要使用 <link> 标签把样式表链接到每个页面,相应的页面就可以使用其中的样式。随后,只要修改了样式表中的样式,改动就会在所有被选中的元素上体现出来,无论这个元素在哪个页面里。这样,既可以做到全站页面外观统一,又便于整站样式更新。

@import 指令

除了以上三种为页面添加样式的方法,还有一种在样式表中链接其他样式表的方法,那就应用 @import 指令(是一种 at 规则):

@import url(css/styles2.css)

要注意的是,@import 指令必须出现在样式表中其他样式之前,否则@import 引用的样式表不会被加载。

注意

CSS 样式是通过 <style> 标签嵌入到页面里的。当浏览器遇到开标签 <style> 时,就会由解释 HTML 代码切换为解释 CSS 代码。等遇到闭标签 </style> 时,它会再切换回解释 HTML 代码。

对于写在样式表里的样式,就不需要 <style> 标签了。如果在样式表里加上这个标签,样式表中的样式就不会被浏览器加载了。

CSS 规则命名惯例

CSS 规则由选择符和声明两部分组成。

选择符用于指出规则所要选择的元素。

声明由两部分组成:属性和值。属性指出要影响元素哪方面的样式,值就是属性的一个新状态。

上下文选择符

上下文选择符,基于祖先或同胞元素选择一个元素。 CSS 规范里,叫后代组合式选择符,就是一组以空格分隔的标签名。用于选择作为指定祖先元素后代的标签。

格式: 标签1 标签2 {声明}

标签 2 是想要选择目标,而且只有在标签 1 是其祖先元素(不一定是 父元素)的情况下才会被选中。

特殊的上下文选择符

子选择符

格式: 标签 1 > 标签 2 {声明}

标签 2 必须是标签 1 的子元素,或者说,标签 1 必须是标签 2 的父元素。与常规的上下文选择符不同,这个选择符中的标签 1 不能是标签 2 的父元素之外的其他祖先元素。

紧邻同胞选择符

格式:标签 1 + 标签 2 {声明}

标签 2 必须紧跟在其同胞标签 1 的后面。

一般同胞选择符

格式:标签 1 ~ 标签 2 {声明}

标签 2必须跟(不一定紧跟)在其同胞标签 1 后面。

通用选择符 *

格式: * {声明}

通用选择符 * (常被称为星号选择符)是一个通配符,它匹配任何元素。

ID 和类选择符

ID 和类为选择元素提供了另一套手段,利用它们可以不用考虑文档的层次结构。

可以给id 和class 属性设定任何值,但不能以数字或特殊符号开头。

类属性

类属性是 HTML 元素的 class 属性,body 标签中包含的任何 HTML 元素都可以添加这个属性。

类选择符

格式: .类名

类选择符就是在 HTML 类名前面加一个点(英文句号)。点(.)、 类名之间没有空格。

标签带类选择符

如果只想瞄准带有这个类的段落,可以把标签名和类选择符写在一块,比如:

p.specialtext {...}

该规则只选择带 specialtext 类的段落。

多类选择符

可以给元素添加多个类,比如:

<p class="specialtext featured">Here the span tag <span>may or may not</span> be styled.</p>

HTML 的 class 属性可以有多个空格分隔的值。

选择同时存在这两个类名的元素:

.specialtext.featured {...}

CSS 选择符的两个类名之间没有空格,因为只想选择同时具有这两个类 名的那个元素。如果加了空格,那就变成了“祖先/后代”关系的上下文选择符了。

每个类名分别用一个 HTML class 属性的做法是常见的错误,正确的做法是像上面的代码那样,只用一个class 属性,但给它设定多个值。

ID 属性

ID 与类的写法相似,表示 ID 选择符的 # 的用法,也跟表示类选择符的 . 类似。

如果有一个段落像下面这样设定了 ID 属性:

<p id="specialtext">This is the special text.</p>

那么,相应的 ID 选择符就是这样的:

#specialtext {...}

或者这样的:

p#specialtext {...}

除此之外,ID 与类的用法都一样,而且前面关于类选择符的(几乎)一 切,都适应于 ID 选择符。

用于页内导航的 ID

ID 也可以用在页内导航链接中。 下面就是一个链接,其目标是同一页的另一个位置:

<a href="#bio">Biography</a>

href 属性值开头的 #, 它表示这个链接的目标在当前页面中,因而不会触发浏览器加载页面(如果没有#,浏览器就会尝试加载 bio 目录下的默认页面了)。

使用与 CSS 选择符里相同的 #ID 名语法,可以把链接导航到同一页面中的目标ID。在这个页面的下方,应该有对应的目标元素:

<h3 id="bio">Biography</h3>
<p>I was born when I was very young…</p>

注意,作为目标的 ID 值前面是没有 # 的,就是一个普通的 ID 值。

用户单击前面的链接时,页面会向下滚动到 ID 值为 bio 的 h3 元素的位置。

如果链接的 href 属性里只有一个 #,那么点击该链接会返回页面顶部: <a href="#">Back to Top</a>

要写一个“返回顶部”链接,不需要 ID 为 # 的目标元素。

如果暂时不知道某个 href 应该放什么 URL,也可以用 # 作为占位符,但不能把该属性留空。因为 href 属性值为空的链接的行为跟正常链接不一样。这样,团队中的其他人将来可以用中间层(比如PHP)变量替换 #,以便动态接收来自数据库的 URL。

什么时候用 ID,什么时候用类

什么时候用 ID

ID 的用途是在页面中唯一地标识一个元素。因此,同一个页面中的每一个 ID 属性,都必须有独一无二的值(名字)。换一个角度讲,每个ID 名在页面中都只能用一次。

也可以使用 ID 把 JavaScript 与某个标签关联起来(比如,当用户鼠标移动到一个链接上面时,运行激活动画的脚本)。ID 值的唯一性对 JavaScript 尤其重要,否则就会导致 JavaScript 行为异常。

<nav id="mainmenu">

在这里,页面中就不能再有其他元素使用 mainmenu 作为 ID 名了。为了标识页面的某一部分,比如主导航菜单,可以为 nav(navigation,导航)添加一个 ID 属性,并让它包含菜单元素。

<nav id="mainmenu">
    <ul>
        <li><a href="#">Yin</a></li>
        <li><a href="#">Yang</a></li>
    </ul>
</nav>

有了用唯一 ID 标识的菜单之后,就可以使用上下文选择符来选择其中包含的各种类型的标签了。

比如,可以将这个菜单中的链接设置为橙色,同时又不会影响页面中 的其他链接:

#mainmenu a {color:orange;}

利用唯一 ID,可以在 CSS 中方便地定位到这个元素,以及它的子元素。可以给页面中每个顶级区域都添加一个 ID,从而得到非常明确的上下文,以便编写 CSS 时只选择嵌套在相应区域内的标签。

什么时候使用类

类的目的是为了标识一组具有相同特征的元素。

在下面这个孩子名字的列表中,要把男孩的名字变成蓝色,把女孩的名字变成粉红色。首先,用类在标记中标识出了性别。

<nav>
    <ul>
        <li class="boy"><a href="#">Alan</a></li>
        <li class="boy"><a href="#">Andrew</a></li>
        <li class="girl"><a href="#">Angela</a></li>
        <li class="boy"><a href="#">Angus</a></li>
        <li class="girl"><a href="#">Anne</a></li>
        <li class="girl"><a href="#">Annette</a></li>
    </ul>
</nav>

然后,再用CSS 为链接应用颜色:

.boy a {color:#6CF;}    /*蓝色*/
.girl a {color:#F9C;}   /*粉红色*/

第一条规则选择所有类名为 boy 的祖先元素包含的 a 元素,第二条规则选择所有类名为 girl 的祖先元素包含的 a 元素。这两种情况下的祖先元素,都是作为相应链接父元素的 li 元素。

不要乱用类

不要像使用 ID 一样,每个类都指定一个不同的类名,然后再为每个类编写规则。

如果你确实有这种随意使用类的习惯,说明还不了解继承和上下文选择符的作用。于是,可能会给每个标签都重复写同样的样式(比如为页面中很多标签分别指定相同的字体)。实际上,继承和上下文选择符能让不同的标签共享样式,从而降低需要编写和维护的 CSS 量。

ID 和 类的小结

ID 的用途是在页面标记中唯一地标识一个特定的元素。它能够为编写CSS 规则提供必要的上下文,排除无关的标记,而只选择该上下文中的标签。

类是可以应用给任意多个页面中的任意多个HTML 元素的公共标识符, 以便为这些元素应用相同的CSS 样式。而且,使用类也让为不同标签名的元素应用相同的样式成为可能。

属性选择符

它基于HTML 标签的属性选择元素。

属性名选择符

格式:标签名[属性名] {...}

选择任何带有属性名的标签名。

示例:

 /* 选择带有title 属性的 HTML img 元素  */
img[title] {...}

属性值选择符

格式:标签名[属性名="属性值"]{...}

在 HTML5 中,属性值的引号可加可不加。

选择任何带有值为属性值的属性名的标签名。

示例:

 /* 选择 title 属性值为 "red flower" 的 HTML img 元素  */
img[title="red flower"] {...}

更多的属性选择符形式

属性选择符小结

基于属性名和属性的其他特征选择元素,提供了另一种区别对待相同标签的 机会。

伪类

到现在为止,介绍的选择符都有一个共同点,即它们针对的都是标记中的某个部分,比如标签名、类名、ID、属性或属性值。

然而,使用CSS 还可以在某些事件发生时,改变某些元素的样式,比如用户鼠标悬停在一个链接上。而这就要靠伪类来实现。

伪类分两种:

  • UI(User Interface,用户界面)伪类,会在 HTML 元素处于某个状态时(比如鼠标指针位于链接上),为该元素应用 CSS 样式。
  • 结构化伪类,会在标记中存在某种结构上的关系时(如某个元素是一组元素中的第一个或最后一个),为相应元素应用 CSS 样式。

UI 伪类

UI 伪类会基于特定 HTML 元素的状态应用样式。

链接伪类

针对链接的伪类一共有 4 个,因为链接始终会处于如下 4 种状态之一:

  • Link。此时,链接就在那儿等着用户点击。
  • Visited。用户此前点击过这个链接。
  • Hover。鼠标指针正悬停在链接上。
  • Active。链接正在被点击(鼠标在元素上按下,还没有释放)。

以下是这些状态对应的 4 个伪类选择符:

a:link {...}
a:visited {...}
a:hover {...}
a:active {...}
/* 由于这4 个伪类的特指度相同,如果不按照这里列出的顺序使用它们,浏览器可能不会显示预期结果。 */

一个冒号(:)表示伪类,两个冒号(::)表示 CSS3 新增的伪元素。浏览器目前都支持对 CSS 1 和 CSS 2 的伪元素使用一个冒号,但希望能习惯于用双冒号代替单冒号,因为这些单冒号的伪元素最终可能都会被淘汰掉

注意,有些伪类可以用于任何元素,而不仅仅是 a 元素。

:focus 伪类

格式:e:focus

e 表示任何元素,如p、h1、section,等等。

:target 伪类

格式:e:target

如果用户点击一个指向页面中其他元素的链接,则那个元素就是目标(target),可以用 `:target 伪类选中它。

示例:

<a href="#more_info">More Information</a>

<!-- 位于页面其他地方、ID 为 more_info 的那个元素就是目标。-->
<h2 id="more_info">This is the information you are looking for.</h2>

那么,

#more_info:target {background:#eee;}

会在用户单击链接转向 ID 为 more_info 的元素时,为该元素添加浅灰色背景。

结构化伪类

结构化伪类可以根据标记的结构应用样式。

:first-child 和 :last-child

格式:

e:first-child
e:last-child

:first-child 代表一组同胞元素中的第一个元素,而 :last-child 则代表最后一个。

示例:

<ol class="results">
    <li>My Fast Pony</li>
    <li>Steady Trotter</li>
    <li>Slow Ol' Nag</li>
</ol>
ol.results li:first-child {color:blue;}

文本 “My Fast Pony” 就会变成蓝色。

如果选择符改成这样:

ol.results li:last-child {color:red;}

那变成红色的文本就是 “Slow Ol’ Nag” 了

补充

那些年踩过的坑之:first-child伪类选择器

  • 只要 E 元素是它的父级的第一个子元素,就选中。它需要同时满足两个条件,一个是“第一个子元素”,另一个是“这个子元素刚好是 E ”。
  • 类似容易误解的结构选择器还有: nth-child()、:nth-last-child、:only-child

:nth-child

格式:

e:nth-child(n)

e 表示元素名,n 表示一个数值(也可以使用 odd 或 even)。

示例:

li:nth-child(3)

会选择一组列表项中的每个第三项。

更多的 伪类

伪元素

伪元素是文档中若有实无的元素。

::first-letter 伪元素

格式:

e::first-letter

选中一整块文字第一行的第一个字母,并且文字所处的行之前没有其他内容(如图片和内联的表格) 。

::first-line 伪元素

格式:

e::first-line

选中文本段落(一般情况下是段落)的第一行。

::before 和 ::after 伪元素

格式:

e::before
e::after

可用于在特定元素前面或后面添加特殊内容。

注意 搜索引擎不会取得伪元素的信息(因为它在标记中并不存在)。因此,不要通过伪元素添加你想让搜索引擎索引的重要内容。

更多关于伪类的内容:

https://developer.mozilla.org/zh-CN/docs/Web/CSS/::first-letter

https://developer.mozilla.org/zh-CN/docs/Web/CSS/Pseudo-classes

https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Introduction_to_CSS/Pseudo-classes_and_pseudo-elements

继承

CSS 中的祖先元素也会向后代传递一样东西:CSS 属性的值。

CSS 中有很多属性是可以继承的,其中相当一部分都跟文本有关,比如颜色、字体、字号。

也有很多CSS 属性不能继承,因为继承这些属性没有意义。这些不能 继承的属性主要涉及元素盒子的定位和显示方式,比如边框、外边距、内边距。

由于字体和文本样式是可以继承的,所以在使用相对字体单位(如百分比和 em )时要格外小心。如果某个标签的字体大小被设置为80%,而它的一个后代的字体大小也被设置为 80%,那么该后代中文本最终的字体大小将是 64%( 80% 的 80% )。

可以参考 CSS参考资料, 每个单独的属性页都会从一个汇总表开始,其中包含有关该元素的各种详细信息,包括是否被继承。

层叠

层叠,是一种样式在文档层次中逐层叠加的过程,目的是让浏览器面对某个标签特定属性值的多个来源,确定最终使用哪个值。

样式来源

浏览器层叠各个来源样式的顺序:

  • 浏览器默认样式表
  • 用户样式表
  • 作者链接样式表(按照它们链接到页面的先后顺序)
  • 作者嵌入样式
  • 作者行内样式

浏览器会按照上述顺序依次检查每个来源的样式,并在有定义的情况下,更新对每个标签属性值的设定。整个检查更新过程结束后,再将每个标签以最终设定的样式显示出来。

层叠规则

层叠规则一:找到应用给每个元素和属性的所有声明

浏览器在加载每个页面时,都会据此查到每一条CSS 规则,标识出所有受到影响的HTML 元素。

层叠规则二:按照顺序和权重排序。浏览器依次检查 5 个来源,并设定匹配的属性

如果匹配的属性在下一个来源也有定义,则更新该属性的值,如此循环,直到检查完页面中所有标签受影响属性的全部 5 个来源为止。最终某个属性被设定成什么值,就用什么值来显示。

声明也可以有权重。可以像下面这样为单独的声明增加权重:

p {color:green !important; font-size:12pt;}

空格 !important 分号(;)用于加重声明的权重。

这条规则加重了将文本设置为绿色的权重。就算层叠的下一来源给段落设定了其他颜色,最终的颜色值仍然还是绿色。说到底,就是一种特权。

层叠规则三:按特指度排序。

特指度表示一条规则有多明确。一条规则的特指度,由它的选择符中包含多少个标签、类名和 ID 决定。

计算特指度

记分规则:对每个选择符都要按下面的 “I-C-E” 公式计算三个值。

三个字母间的短横线是分隔符,并非减号。针对这个公式的计分办法如下:

  1. 选择符中有一个 ID,就在 I 的位置上加 1;
  2. 选择符中有一个类,就在 C 的位置上加 1;
  3. 选择符中有一个元素(标签)名,就在 E 的位置上加 1;
  4. 得到一个三位数。

示例:

选择符 I-C-E 特指度
P 0-0-1 1
p.largetext 0-1-1 11
p#largetext 1-0-1 101
body p#largetext 1-0-2 102
body p#largetext ul.mylist 1-1-3 113
body p#largetext ul.mylist lit 1-1-4 114

在此,每个选择符都比前一个选择符的特指度更高。

层叠规则四:顺序决定权重

如果两条规则都影响某元素的同一个属性,而且它们的特指度也相同,则位置最靠下(或后声明)的规则胜出。

层叠要点

  • 规则一:包含 ID 的选择符胜过包含类的选择符,包含类的选择符胜过包含标签名的选择符。

  • 规则二:如果几个不同来源都为同一个标签的同一个属性定义了样式,行内样式胜过嵌入样式,嵌入样式胜过链接样式。在链接的样式表中,具有相同特指度的样式,后声明的胜过先声明的。

  • 规则一胜过规则二。换句话说,如果选择符更明确(特指度更高),无论它在哪里,都会胜出。(存在疑问:内联样式应该比 ID 更高)

  • 规则三:设定的样式胜过继承的样式,此时不用考虑特指度(即显式设定优先)。

下面简单解释一下规则三。比如下面的标记:

<div id="cascade_demo">
    <p id="inheritance_fact">Inheritance is <em>weak</em> in the Cascade</p>
</div>

和下面的规则:

div#cascade_demo p#inheritance_fact {color:blue;}
/* 2 - 0 - 2 (高特指度) */

会导致单词 “weak” 变成蓝色,因为它从父元素 p 那里继承了这个颜色值。但是,只要再给 em 添加一条规则:

em {color:red;}
/* 0 - 0 - 1 (低特指度) */

em 就会变成红色。因为,虽然它的特指度低(0-0-1),但 em 继承的颜色值,会被为它明确(显式)指定的颜色值覆盖,就算(隐式)遗传该颜色值的规则的特指度高(2-0-2)也没有用。

规则声明

一个声明包含两部分:属性和值。属性指出要影响元素的哪个方面(颜色、高度,等等),而值表示把属性设定为什么(绿色、12px,等等)。

每个元素都有很多属性,每个元素都有很多属性。

CSS 属性值主要分以下三类:

  • 文本值。
    • 例如,font-weight:bold 声明中的 bold 就一个文本值。文本值也叫做关键字。
  • 数字值。
    • 数字值后面都有一个单位,例如英寸或点。
    • 在声明 font-size:12px 中,12 是数字值,而 px 是单位(像素)。如果数字值为 0,那么就不用带单位了。
  • 颜色值。
    • 颜色值可以用几种不同的格式来写,包括RGB(Red, Green, Blue,红绿蓝)、HSL(Hue, Saturation, Luminance,色相,饱和度,亮度)和十六进制值(例如 color:#336699)。

文本值

所有CSS 属性都有文本值

数字值

数字值主要分两类:绝对值和相对值。

绝对值描述的是一个真实的长度(比如,6 英寸),而相对值 则是相对于其他基准的描述(比如“是某某的两倍长”)。

绝对值及示例

绝 对 值 单位缩写 示 例
英寸 in height: 6in
厘米 cm height: 40cm
毫米 mm height: 500mm
pt height: 60pt
皮卡 pc height: 90pc
像素 px height: 72px

打印纸是以英寸为单位度量的。

相对值及示例

相 对 值 单位缩写 示 例
Em em height:1.2em
Ex ex height:6ex
百分比 % height:120%

em 和 ex 都是字体大小的单位,但在CSS 中,它们作为长度单位适用于任何元素。

em ,它表示一种字体中字母 M 的宽度,因此它的具体大小取决于你使用的字体。

ex ,等于给定字体中字母 x 的高度(小写字母 x 代表一种字体的字母中间部分的高度,不包括字母上、下突出的部分——如 d 和 p 上下都出头儿)。

百分比非常适合设定被包含元素的宽度,此时的百分比就是相对于宽度而言的。

颜色值

颜色名

设定颜色属性时可以直接使用颜色关键字。

W3C 定义了 16 个颜色关键字:

颜色关键字
aqua(浅绿色) black(黑色) blue(蓝色)
fuchsia(紫红色) gray(灰色) green(绿色)
lime(黄绿色) maroon(褐红色) navy(深蓝色)
olive(茶青色 ) purple(紫色) red(红色)
silver(银色) teal(青色) white(白色)
yellow(黄色)

要了解这些颜色名及其对应的 RGB 颜色值,可以参 考:http://www.w3.org/TR/css3-color/#html4。

十六进制颜色(#RRGGBB 或 #RGB)

格式:

#rrggbb

示例:

/* 橙色 */
#ff8800

这个 6 位数的前两位定义红色,中间两位定义绿色,后两位定义蓝色。

RGB 颜色值(R, G , B)

每种颜色都可以用一个 0 到 255(包含)之间的值指定。

格式如下:

rgb(r, g, b)

示例:

rgb(0,255,0)

表示纯绿色。

RGB 百分比值(R%, G%, B%)

这是用百分比来表示每种颜色值的一种方法。 格式:

r%, g%, b%

可以接受的值是 0% 到 100% 。这种方法只能表示区区一百万(100 × 100 × 100)种颜色。

使用百分比表示的颜色值,比使用十六进制更容易猜到你想要的颜色。举个例子,100%, 0%, 0% 是纯红色,0%, 100%, 0%是 纯绿色。

HSL (色相 , 饱和度 %, 亮度 %)

格式:

HSL(0,0%,0%)

HSL 颜色中的第一个值表示色相,也就是一个实际的颜色,比如红色和绿色。所有颜色围绕色相环(也叫色轮)一周,而色相值以圆周上的度数表示。

饱和度设定有多少颜色。<br> 灰色的饱和度低,而强烈的色彩饱和度高。

亮度设定颜色的明暗。<br> 0% 就是黑色,100% 就是白色,而中间的值是实际能看到的色相。

HSL 只有一个表示颜色的值。把饱和度和亮度都设定为 50%,就可以调制出 想要的任何颜色来。

Alpha 通道

RGB 和 HSL 都支持 Alpha 通道,用于设置颜色的不透明度(换句话说,就是能够透过多少背景)。<br> 相应的格式分别叫 RGBA 和 HSLA。其中,两种格式中的 A (alpha)值可以是 1(完全不透明)也可以是 0(完全透明),或者介于1 和 0 之间的小数值。